/*
 * CNetWorkApp.cpp
 *
 *  Created on: 2011-10-15
 *      Author: dvrzy
 */

#include "CStreamLayer.h"
#include "AssemblyFileHeader.h"
#include "CSessionManager.h"
#include "SystemConfig.h"
#include "ConfigJsonKeyword.h"
#include "Defines.h"

//	设备网络层启动远程多路同步回放接口
//Input param：
//@ssid 有pt与ssrc组合产生唯一的id
//@ startTime回放开始时间
//@ endTime 回放结束时间
//@ streamType 回放视频的类型
//@ videotype	 录像文件类型
//@ chno回放视频的通道号 bit位表示,bit0-bit31表示通道1-通道32
//		Output param：@ streamed 返回一个句柄，该句柄唯一表示该回放任务
//			Return：0：成功，-1：失败,-2:达到用户最大申请数
 int CStreamLayer::StartRemotePlayBack(const unsigned int ssid,unsigned int chno,
		 	 	 	 	 	 	 	 StreamType streamType,VideoType videotype,DateInfo_Tag startTime,
		 	 	 	 	 	 	 	 DateInfo_Tag endTime,taskSession_node*	currentsession)
 {
//
 	unsigned int nGroupid 	= 1;
 	int nchnnum 				= 0;

 	nGroupid					= CSessionManager::GetInstance()->GetPalyBackId();

 	if(nGroupid < 0)
 	{
 		return -2;
 	}

// 	msgStartPlayback_t stuPlayback;
// 	memset(&stuPlayback,0,sizeof(msgStartPlayback_t));
//
// 	stuPlayback.iPlaybackMode		= 0;
// 	stuPlayback.iGroupId 			= nGroupid;
// 	stuPlayback.iChlMask 			= chno;
// 	switch(videotype)
// 	{
// 	case NORMALVIDEO:
// 		stuPlayback.iRecordTypeMask = 0x01;
// 		break;
// 	case ALARMVIDEO:
// 		stuPlayback.iRecordTypeMask = 0x02;
// 		break;
// 	case ALARM_NOR:
// 		stuPlayback.iRecordTypeMask = 0x03;
// 		break;
// 	}
//
// 	switch(streamType)
// 	{
// 		case SUBSTREAM:
// 			stuPlayback.iStreamType	= 0;
// 			break;
// 		case MAINSTREAM:
// 			stuPlayback.iStreamType	= 1;
// 			break;
// 		case MOBILESTREAM:
// 			stuPlayback.iStreamType 	= 2;
// 			break;
// 		default:
// 			stuPlayback.iStreamType 	= 1;
// 			break;
// 	}

// 	stuPlayback.unPlaybackParam.stuTime.year 			= startTime.date_YMD.year;
// 	stuPlayback.unPlaybackParam.stuTime.month	 		= startTime.date_YMD.month;
// 	stuPlayback.unPlaybackParam.stuTime.day 			= startTime.date_YMD.day;
// 	stuPlayback.unPlaybackParam.stuTime.hour 			= startTime.date_HMS.hour;
// 	stuPlayback.unPlaybackParam.stuTime.minute 		= startTime.date_HMS.minute;
// 	stuPlayback.unPlaybackParam.stuTime.second		= startTime.date_HMS.second;
 	currentsession->palybackid							= nGroupid	;
// 	//在发送消息前添加任务节点
 	_taskmutex.ThreadLock();
 	if(myList.find(currentsession->task_ssid) == myList.end())
 	{
 		myList[currentsession->task_ssid]	= currentsession;
 		//DEBUG_WARNING("--------------add  new node--task_ssid-:[%d]------nGroupid:[%d]--------\n",currentsession->task_ssid,nGroupid);
 	}
 	else
 	{
 		_taskmutex.ThreadUnlock();
 		return -3;
 	}
 	_taskmutex.ThreadUnlock();

 	for(int index = 0; index < HARDWARE_VIDEO_CHANNEL_NUM; index++)
 	{
 		if(chno & (0x01 << index))
 		{
 			nchnnum++;
 		}
 	}

 	CSyncPlaybackStream* pStream						= NULL;
 	pStream												= new CSyncPlaybackStream(nGroupid, nchnnum, startTime, endTime);
 	currentsession->dev									= (void*)pStream;

 	DEBUG_WARNING("--------------PlayBackpid:[%d]---------this:[%d]--------------\n",getpid(),(int)this);
// 	DEBUG_WARNING("----------streamType:[%d]-------[%d-%d-%d %d:%d:%d]---------currentsession:[%d]------this:[%d]-----------\n",stuPlayback.iStreamType,stuPlayback.unPlaybackParam.stuTime.year,stuPlayback.unPlaybackParam.stuTime.month,stuPlayback.unPlaybackParam.stuTime.day,stuPlayback.unPlaybackParam.stuTime.hour,stuPlayback.unPlaybackParam.stuTime.minute,stuPlayback.unPlaybackParam.stuTime.second,(int)currentsession,(int)currentsession->ptrstreamlyer);
// 	_messageClient->SendMessage(0, MESSAGE_STORAGE_PLAYBACK_START, 1, (char*)&stuPlayback, sizeof(msgStartPlayback_t), (int)currentsession);
 	DEBUG_WARNING("------------------------ssid:[%d]------ssrc:[%d]-----------\n",currentsession->ssid,currentsession->ssrc	);


 	return 0;
 }

//设备网络层获取视频数据
//Input param：@ ssid 回放任务句柄
//
//Outputparam：@ data 当前视频数据
//				 @ channel 实际通道号
//formattype 0：表示帧数据,1:表示格式
//flag	: 是否是新的流段 0：本流段 1：流段开始 2:流段结束
//Return：	0：成功，-1失败,-2没有数据, -3 结束, -4 正在解析
int CStreamLayer::GetRemotePlayBackData(taskSession_node*	currentsession,unsigned char **datafirst,int &datalenfirst,
											unsigned char **dataSecond,int &datalenSecond,int & formattype,int &freamtype,
											int &channel,unsigned int &flag,int &chnindex)
{
	if(currentsession && currentsession->dev)
	{
		uint64_t uPTS 		=0;
		return ((CSyncPlaybackStream* )currentsession->dev)->GetSyncPlaybackData(datafirst, datalenfirst,dataSecond,datalenSecond,channel, formattype,freamtype, uPTS, flag,chnindex);
	}

	return -1;
}

int	CStreamLayer::ReleasePlayBackFream(taskSession_node*	currentsession,const int chnindex)
{
	if(currentsession && currentsession->dev)
	{
		return ((CSyncPlaybackStream* )currentsession->dev)->ReaseSyncPlaybackFream(chnindex);
	}
	return -1;
}

//	设备网络层获取各个通道视频数据状态，有的通道可能没有录像，有的通道有录像，实时告诉pc层回放时各个通道的有无视频的状态。
//Input param：@ streamed 回放任务句柄
//				:@ channelmask通道号掩码，bit0-bit31表示通道1-通道32，对应bit位为1时有效
//Outputparam：@ chnostate bit位表示当前回放任务中各个通道的状态，如果有视频数据则为1，没有则为0。Bit0-bit31表示通道1-通道32
//Return：	0：成功，-1失败
int CStreamLayer::GetRemotePlayBackChnoState(taskSession_node*	currentsession,unsigned int &chnostate,unsigned int channelmask)
{
	chnostate = 0;

	if(currentsession && currentsession->dev)
	{
		for(int chn = 0; chn < HARDWARE_VIDEO_CHANNEL_NUM; chn++)
		{
			if(channelmask & (0x01 << chn))
			{
				if(((CSyncPlaybackStream* )currentsession->dev)->GetChnStatus(chn) == 2)
				{
					chnostate |= (0x01 << chn);
				}
			}
		}
		return 0;
	}
	else
	{
		DEBUG_WARNING("-------------------it-is--error---\n");
	}

	return -1;
}

//设备网络层检测远程多路同步回放任务状态。
//如果回放任务结束了，就通知网络层回放任务结束，同时网络层也会通知pc上层结束回放任务。
//Input param：@ ssid 回放任务句柄
//Return：结束返回0，未结束返回-1
int CStreamLayer::CheckRemotePlayBackResult(taskSession_node*	currentsession)
{
	if(currentsession && currentsession->dev)
	{
		if(((CSyncPlaybackStream* )currentsession->dev)->IsOver())
		{
			return 0;
		}
	}

	return -1;
}

//设网络层通知设备底层停止回放任务
//设备网络层检测网络异常或者接受到停止的指令后，自动释放网络资源，同时要通知设备底层释放回放占用的资源。
//Input param：@ ssid 回放任务句柄
//				@ currentsession 回放任务节点
//Return： 0：成功， -1：失败
int CStreamLayer::StopRemotePlayBack(const unsigned int ssid,taskSession_node*	currentsession)
{
//	std::map<unsigned int, CSyncPlaybackStream*>::iterator inter;
//	DEBUG_WARNING("--------------ssid-:[%d]--------------\n",ssid);
//	if((inter = _handlePlaybackStream.find(ssid)) != _handlePlaybackStream.end())   /*已经有对应的 _handlePlaybackStream了*/
//	{
//		CSyncPlaybackStream* pStream = _handlePlaybackStream[ssid];
//	}

	if(currentsession && currentsession->dev)
	{
		if(myList.find(currentsession->task_ssid) != myList.end())
		{
			DEBUG_WARNING("--------------task_ssid-:[%d]--------------\n",currentsession->task_ssid);
			CSyncPlaybackStream* pStream	= (CSyncPlaybackStream*)currentsession->dev;
		//	msgStopPlayback_t stuStopPlayback;
// 			stuStopPlayback.iGroupId = currentsession->palybackid;
// 			_messageClient->SendMessage(0, MESSAGE_STORAGE_PLAYBACK_STOP, 1, (char*)&stuStopPlayback, sizeof(msgStopPlayback_t), (int)currentsession);
			if(pStream)
			{
				delete pStream;
			}
			pStream = NULL;
			CSessionManager::GetInstance()->FreePalyBackId(currentsession->palybackid);
			return 0;
		}
	}

	return -1;
}

//	设备网络层拖拽通知设备
//客户端下发指令给设备seek到指定的位置，要求设备能迅速的响应，网络延时及设备查找延时应该保证在1-2S内完成，在带宽好的情况下500ms内就能完成seek动作。
//考虑到如果出现多任务运行下，设备负载会很大，seek的延时也会相应的延长，但必须保证能尽可能的迅速响应，网络在传输数据时也要迅速，让延时将至最低。
//Input param：@ currentsession 回放任务
//			   @ SeekTime时间
//Return： 0：成功， -1：失败
int CStreamLayer::SeekRemotePlayBack(taskSession_node*	currentsession,DateInfo_Tag SeekTime)
{
// 	DEBUG_WARNING("--------------PlayBackpid:[%d]---------this:[%d]--------------\n",getpid(),(int)this);
// 
// 	if(currentsession && currentsession->dev)
// 	{
// 		msgPlaybackOperate_t stuPlaybackOperate;
// 		stuPlaybackOperate.iGroupId 						= ((CSyncPlaybackStream* )currentsession->dev)->GetGroupid();
// 		stuPlaybackOperate.iOperate 						= 1;
// 		stuPlaybackOperate.unOperateData.stuSeek.year		= SeekTime.date_YMD.year;
// 		stuPlaybackOperate.unOperateData.stuSeek.month	= SeekTime.date_YMD.month;
// 		stuPlaybackOperate.unOperateData.stuSeek.day		= SeekTime.date_YMD.day;
// 		stuPlaybackOperate.unOperateData.stuSeek.hour 	= SeekTime.date_HMS.hour;
// 		stuPlaybackOperate.unOperateData.stuSeek.minute 	= SeekTime.date_HMS.minute;
// 		stuPlaybackOperate.unOperateData.stuSeek.second 	= SeekTime.date_HMS.second;
// 		stuPlaybackOperate.unOperateData.stuSeek.pts		= currentsession->offset;
// 
// // 		_messageClient->SendMessage(0, MESSAGE_STORAGE_PLAYBACK_OPERATE, 1, (char*)&stuPlaybackOperate, sizeof(msgPlaybackOperate_t), (int)currentsession);
// 
// 		return 0;
// 	}

	return -1;
}

//	设备网络层快进通知设备
//考虑如果是D1的录像文件，由于数据量大，设备网络传送的数据量无法满足pc客户端快进倍率，适当的情况下需要只上传I帧
//此要求倍率需在4倍率，切回放的录像文件是主码流,丢掉全部p帧。
//Input param：@ currentsession 回放任务
//Return： 0：成功， -1：失败
int CStreamLayer::ForwardRemotePlayBack(taskSession_node*	currentsession,int cmdtype)
{
	DEBUG_WARNING("--------------PlayBackpid:[%d]---------this:[%d]--------------\n",getpid(),(int)this);

// 	if(currentsession && currentsession->dev)
// 	{
// 		switch(cmdtype)
// 		{
// 		case 2:
// 			{
// 				msgPlaybackOperate_t stuPlaybackOperate;
// 				memset(&stuPlaybackOperate,0,sizeof(stuPlaybackOperate));
// 				stuPlaybackOperate.iGroupId 						= currentsession->palybackid;
// 				stuPlaybackOperate.iOperate 						= 3;
// 				stuPlaybackOperate.unOperateData.stuPlay.hour		= 0xff;
// 				stuPlaybackOperate.unOperateData.stuPlay.minute	= 0xff;
// 				stuPlaybackOperate.unOperateData.stuPlay.second	= 0xff;
// 
// // 				_messageClient->SendMessage(0, MESSAGE_STORAGE_PLAYBACK_OPERATE, 1, (char*)&stuPlaybackOperate, sizeof(msgPlaybackOperate_t), (int)currentsession);
// 			}
// 			break;
// 		case 3:
// 			{
// 				msgPlaybackOperate_t stuPlaybackOperate;
// 				memset(&stuPlaybackOperate,0,sizeof(stuPlaybackOperate));
// 				stuPlaybackOperate.iGroupId 						= currentsession->palybackid;
// 				stuPlaybackOperate.iOperate 						= 0;
// 
// // 				_messageClient->SendMessage(0, MESSAGE_STORAGE_PLAYBACK_OPERATE, 1, (char*)&stuPlaybackOperate, sizeof(msgPlaybackOperate_t), (int)currentsession);
// 			}
// 			break;
// 		}
// 		return 0;
// 	}

	return -1;
}

/******************************************************************************************************************************************************************************************/
/*******************************************************************************媒体接口定义************************************************************************************************/


